package com.xbai.config;

import com.xbai.bean.Color;
import com.xbai.bean.ColorFactoryBean;
import com.xbai.bean.Person;
import com.xbai.bean.Red;
import com.xbai.condition.LinuxCondition;
import com.xbai.condition.MyImportBeanDefinitionRegistrar;
import com.xbai.condition.MyImportSelector;
import com.xbai.condition.WindowsCondition;
import org.springframework.context.annotation.*;

/**
 * @author xbai
 * @Date 2021/3/26
 */
// 配置类 == 配置文件
@Configuration // 告诉 Spring 这是一个配置类
//类中组件统一设置 满足当前条件，这个类汇总配置的所有 bean 注册才能生效
@Conditional({WindowsCondition.class})
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) // 导入主键，id默认是组件的全类名
public class MainConfig2 {

    @Bean
    public ColorFactoryBean colorFactoryBean() {
        return new ColorFactoryBean();
    }

    /**
     * 给容器中注册组件
     * 1)、包扫描 + 组件标注注解（@Controller/@Service/@Repository/@Component）
     * 2）、@Bean[导入的第三方包里面的组件]
     * 3）、@Import[快速给容器中导入组件]
     *      1）、@Import(要导入到容器中的组件)：容器中就会自动注册这个组件，id 默认是全类名
     *      2)、@ImportSelector：返回需要导入的组件的全类名数组
     *      3)、ImportBeanDefinitionRegistrar：手动注册 bean 到容器中
     * 4)、使用 Spring 提供的 FactoryBean（工厂Bean）
     *      1)、默认获取到的是工厂 bean 调用 getObject 创建的对象
     *      2)、要获取工厂 Bean 本身，我们需要给 id 前面加一个 & （&colorFactoryBean）
     */

    /**
     * 默认单实例的
     * 使用 @Scope 调整作用域
     * ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * ConfigurableBeanFactory#SCOPE_SINGLETON
     * org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
     * org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
     *
     * prototype：多实例的；ioc 容器启动并不会去调用方法创建对象放在容器中
     *              每次获取的时候才会调用方法创建对象
     * singleton：单实例的（默认值）；ioc 容器启动会调用该方法创建对象放到 ioc 容器中
     *              以后每次获取就是直接从容器（map.get()）中拿
     * request：同一次请求创建一个实例
     * session：同一个session创建一个实例
     *
     *
     * 懒加载：
     *  针对单实例 bean：默认在同期启动的时候创建对象
     *  懒加载：容器启动不创建对象。第一次使用（获取）Bean 创建对象，并初始化
     * @return
     */
    @Bean
//    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Lazy
    public Person person() {
        System.out.println("给容器中添加 person....");
        return new Person("xbai", "20");
    }


    /**
     *  @Conditional：按照一定的条件进行判断，满足条件给容器中注册 bean
     *  如果系统是 windows，给容器中注册 windows
     *  如果是 linux 系统，给容器中注册 linux
     */
    @Bean
    @Conditional({WindowsCondition.class})
    public Person windows() {
        return new Person("windows", "20");
    }

    @Bean
    @Conditional({LinuxCondition.class})
    public Person linux() {
        return new Person("linux", "20");
    }
}
